from django import forms
from openlabyrinth.models import *

BOOLEAN_CHOICES = (
    (False, 'Disabled'),
    (True, 'Enabled')
)

VISIBILITY_CHOICES = (
    (False, 'Hidden'),
    (True, 'Visible')
)

class LoginForm(forms.Form):
    username = forms.CharField(max_length=64, 
        widget=forms.TextInput(attrs={'class':'x-form-text x-form-field'}))
    password = forms.CharField(
        widget=forms.PasswordInput(attrs={'class':'x-form-text x-form-field'}))

class LabyrinthForm(forms.ModelForm):
    class Meta:
        model = Labyrinth

class NodeForm(forms.ModelForm):
    random_outbound_link = forms.BooleanField(required=False, initial=False, widget=forms.Select(choices=BOOLEAN_CHOICES))
    undo = forms.BooleanField(required=False, initial=False, widget=forms.Select(choices=BOOLEAN_CHOICES))
    class Meta:
        model = Node
        exclude = ('labyrinth', 'section', 'section_index', 'x_position', 'y_position', 'color')

class LinkForm(forms.ModelForm):
    class Meta:
        model = Link
        exclude = ('labyrinth', 'source')

class CounterForm(forms.ModelForm):
    visible = forms.BooleanField(label='Visibility', required=False, initial=False, widget=forms.Select(choices=VISIBILITY_CHOICES))
    class Meta:
        model = Counter
        exclude = ('labyrinth',)

class FeedbackForm(forms.ModelForm):
    
    # Feedback objects can't be fully validated using a per-field approach.
    # This function is responsible for doing form-wide checking. As a result,
    # invalid field combinations are avoided and reported to the user.
    def clean(self):
        if self.cleaned_data['type'] == 'time':
            if self.cleaned_data['comparison_value'] == None:
                if not self._errors.has_key('comparison_value'):
                    self._errors['comparison_value'] = forms.util.ErrorList(['This field is required.'])
                else:
                    self._errors['comparison_value'].append(u'This field is required.')
                raise forms.ValidationError(u'A comparison value must be specified for this type of feedback.')
        elif self.cleaned_data['type'] == 'node':
            if self.cleaned_data['node'] == None:
                if not self._errors.has_key('node'):
                    self._errors['node'] = forms.util.ErrorList(['This field is required.'])
                else:
                    self._errors['node'].append(u'This field is required.')
                raise forms.ValidationError(u'A node must be specified for this type of feedback.')
        elif self.cleaned_data['type'] == 'node_type':
            if self.cleaned_data['comparison_value'] == None:
                if not self._errors.has_key('comparison_value'):
                    self._errors['comparison_value'] = forms.util.ErrorList(['This field is required.'])
                else:
                    self._errors['comparison_value'].append(u'This field is required.')
                raise forms.ValidationError(u'A comparison value must be specified for this type of feedback.')
        elif self.cleaned_data['type'] == 'counter':
            errorOccurred = False
            if self.cleaned_data['counter'] == None:
                if not self._errors.has_key('counter'):
                    self._errors['counter'] = forms.util.ErrorList(['This field is required.'])
                else:
                    self._errors['counter'].append(u'This field is required.')
                errorOccurred = True
            if self.cleaned_data['comparison_value'] == None:
                if not self._errors.has_key('comparison_value'):
                    self._errors['comparison_value'] = forms.util.ErrorList(['This field is required.'])
                else:
                    self._errors['comparison_value'].append(u'This field is required.')
                errorOccurred = True
                
            if errorOccurred:
                raise forms.ValidationError(u'Both a counter and comparison value must be specified for this type of feedback.')
                
        return self.cleaned_data
    
    class Meta:
        model = Feedback
        exclude = ('labyrinth',)

class QuestionForm(forms.ModelForm):
    class Meta:
        model = Question
        exclude = ('labyrinth',)

class AvatarForm(forms.ModelForm):
    class Meta:
        model = Avatar
        exclude = ('labyrinth',)

class RemoteStateObserverForm(forms.ModelForm):
    class Meta:
        model = RemoteStateObserver
        exclude = ('labyrinth',)

class AssetForm(forms.ModelForm):
    class Meta:
        model = Asset
        exclude = ('labyrinth',)

class SectionForm(forms.ModelForm):
    nodes = forms.CharField(widget=forms.HiddenInput, required=False)
    class Meta:
        model = Section
        exclude = ('labyrinth')

class RemoteStateObserverForm(forms.ModelForm):
    enabled = forms.BooleanField(label='State', required=False, initial=True, widget=forms.Select(choices=BOOLEAN_CHOICES))
    class Meta:
        model = RemoteStateObserver
        exclude = ('labyrinth',)

class UserForm(forms.ModelForm):
    class Meta:
        model = User

VPD_ELEMENT_TYPES = (
    ('vpd_text', 'VPD Text'),
    ('structured_patient_demographics', 'Structured Patient Demographics'),
    ('unstructured_patient_demographics', 'Unstructured Patient Demographics'),
    ('author_diagnoses', 'Author Diagnoses'),
    ('medication', 'Medication'),
    ('interview_item', 'Interview Item'),
    ('physical_exam', 'Physical Exam'),
    ('diagnostic_test', 'Diagnostic Test'),
    ('differential_diagnosis', 'Differential Diagnosis'),
    ('intervention', 'Intervention')
)

class ElementForm(forms.ModelForm):
    vpd_element_type = forms.ChoiceField(choices=VPD_ELEMENT_TYPES, label='VPD element type')
    
    # Ensure that the element_type field appears first.
    def __init__(self, *args, **kwargs):
        super(ElementForm, self).__init__(*args, **kwargs)
        sorted_fields = self.fields.keys()
        sorted_fields.remove('vpd_element_type')
        sorted_fields.insert(0, 'vpd_element_type')
        self.fields.keyOrder = sorted_fields

class VPDTextForm(ElementForm):
    class Meta:
        model = VPDText
        exclude = ('labyrinth',)

class StructuredPatientDemographicsForm(ElementForm):
    class Meta:
        model = StructuredPatientDemographics
        exclude = ('labyrinth',)

class UnstructuredPatientDemographicsForm(ElementForm):
    class Meta:
        model = UnstructuredPatientDemographics
        exclude = ('labyrinth',)

class AuthorDiagnosesForm(ElementForm):
    class Meta:
        model = AuthorDiagnoses
        exclude = ('labyrinth',)

class MedicationForm(ElementForm):
    class Meta:
        model = Medication
        exclude = ('labyrinth',)

class InterviewItemForm(ElementForm):
    class Meta:
        model = InterviewItem
        exclude = ('labyrinth',)

class PhysicalExamForm(ElementForm):
    class Meta:
        model = PhysicalExam
        exclude = ('labyrinth',)

class DiagnosticTestForm(ElementForm):
    class Meta:
        model = DiagnosticTest
        exclude = ('labyrinth',)

class DifferentialDiagnosisForm(ElementForm):
    class Meta:
        model = DifferentialDiagnosis
        exclude = ('labyrinth',)

class InterventionForm(ElementForm):
    class Meta:
        model = Intervention
        exclude = ('labyrinth',)

class ClusterForm(forms.ModelForm):
    items = forms.CharField(widget=forms.HiddenInput, required=False)
    class Meta:
        model = Cluster
        exclude = ('labyrinth',)

LICENCE_CHOICES = (
    ('public_domain', 'public domain (no restrictions)'),
    ('GNU Public Licence v2', 'GNU Public Licence v2'),
    ('GNU Public Licence v3', 'GNU Public Licence v3'),
    ('Creative Commons: Attribution', 'Creative Commons: Attribution'),
    ('Creative Commons: Attribution Share Alike', 'Creative Commons: Attribution Share Alike'),
    ('Creative Commons: Attribution No Derivatives', 'Creative Commons: Attribution No Derivatives'),
    ('Creative Commons: Attribution Non-Commercial', 'Creative Commons: Attribution Non-Commercial'),
    ('Creative Commons: Attribution Non-Commercial Share Alike', 'Creative Commons: Attribution Non-Commercial Share Alike'),
    ('Creative Commons: Attribution Non-Commercial No Derivatives', 'Creative Commons: Attribution Non-Commercial No Derivatives'),
    ('all_rights_reserved', 'all rights reserved')
)

class LabyrinthExportForm(forms.Form):
    licence = forms.ChoiceField(choices=LICENCE_CHOICES, label='Licence')